package com.uinnova.product.eam.init.ocean;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.Local;
import com.binary.framework.bean.SimpleUser;
import com.binary.framework.exception.ServiceException;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.comm.model.OceanDiagram;
import com.uinnova.product.eam.comm.model.OceanProject;
import com.uinnova.product.eam.comm.model.OceanSystem;
import com.uinnova.product.eam.comm.model.es.EamArtifact;
import com.uinnova.product.eam.comm.model.es.EamDiagramRelationSys;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.es.EamDiagramRelationSysDao;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.db.eam.ESDiagramDao;
import com.uino.bean.cmdb.base.LibType;
import com.uino.service.cmdb.microservice.impl.CIClassSvc;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SyncOceanSvc {

    @Resource
    private CIClassSvc ciClassSvc;
    @Resource
    private ICISwitchSvc iciSwitchSvc;
    @Resource
    private OceanProjectService oceanProjectService;
    @Resource
    private OceanSystemService oceanSystemService;
    @Resource
    private OceanDiagramService oceanDiagramService;
    @Resource
    private BmConfigSvc bmConfigSvc;
    @Resource
    private ESDiagramDao esDiagramDao;
    @Resource
    private IEamArtifactSvc iEamArtifactSvc;
    @Resource
    private EamDiagramRelationSysDao eamDiagramRelationSysDao;

    private boolean isSyncing = false;

    public void syncOceanData() {

        if (isSyncing) {
            log.info("已有任务正在同步！");
            return;
        }
        isSyncing = true;
        try {
            /**
             * 从视图配置中获取配置信息
             */
            String config = bmConfigSvc.getConfigType("INTERFACE_DATA_CONFIG");
            if (StrUtil.isEmpty(config)) {
                log.error("syncOceanData 无法获取视图配置项：INTERFACE_DATA_CONFIG");
                return;
            }
            try {
                boolean open = Local.isOpen();
                try {
                    if(!open) {
                        SimpleUser user = new SimpleUser();
                        user.setId(9999l);
                        user.setDomainId(1l);
                        user.setLoginCode("system");
                        user.setUserName("system");
                        // 模拟当前登录用户
                        Local.open(user);
                    }
                    syncSystem(config);
                    syncProject(config);
                    syncDiagram();
                    if(!open) Local.commit();
                } catch(Throwable t) {
                    Local.rollback();
                    throw t;
                } finally {
                    if(!open) Local.close();
                }
            } catch(Throwable t) {
                throw BinaryUtils.transException(t, ServiceException.class);
            }
        } catch (Exception exception) {
            log.error("syncOceanData 异常！" + exception.getMessage());
        } finally {
            isSyncing = false;
        }

    }

    /**
     * 同步系统资产至数据库，系统数量大概600左右，采用先删后增
     */
    public void syncSystem(String config) {
        log.info("开始同步系统数据。。。。。。");

        // region 配置项检查
        JSONObject jsonConfig = JSON.parseObject(config);
        String systemClassName = jsonConfig.getJSONObject("classMap").getString("系统");
        if (BinaryUtils.isEmpty(systemClassName)) {
            log.error("syncSystem 无法获取视图配置项：系统");
            return;
        }
        /**
         * 属性字段
         */
        JSONObject systemMap = jsonConfig.getJSONObject("systemMap");
        if (BinaryUtils.isEmpty(systemMap)) {
            log.error("syncSystem 无法获取视图配置项：systemMap");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("systemNum"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.systemNum");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("systemName"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.systemName");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("systemShortName"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.systemShortName");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("businessUnit"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.businessUnit");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("buildTeam"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.buildTeam");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("systemStatus"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.systemStatus");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("operateStatus"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.operateStatus");
            return;
        }
        if (BinaryUtils.isEmpty(systemMap.getString("systemType"))) {
            log.error("syncSystem 无法获取视图配置项：systemMap.systemType");
            return;
        }
        // endregion

        // 查询EA系统中对应的对象分类
        CCcCiClass cCcCiClass = new CCcCiClass();
        cCcCiClass.setClassNameEqual(systemClassName);
        List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryCiClassInfoList(1L, cCcCiClass, null, false);
        if (null == ccCiClassInfos || ccCiClassInfos.size() == 0) {
            log.error("syncSystem EA系统中不存在[{}]的对象分类", systemClassName);
            return;
        }
        Long systemClassId = ccCiClassInfos.get(0).getCiClass().getId();

        // 查询系统资产数据
        CCcCi cdt = new CCcCi();
        cdt.setClassId(systemClassId);
        List<CcCiInfo> ccCiInfos = iciSwitchSvc.queryCiInfoList(1l, cdt, null, false, false, LibType.DESIGN);

        // 组织入库数据
        List<OceanSystem> oceanSystems = new ArrayList<>();
        for (CcCiInfo ccCiInfo : ccCiInfos) {
            Map<String, String> ciAttrs = ccCiInfo.getAttrs();
            OceanSystem oceanSystem = new OceanSystem();
            oceanSystem.setCiCode(ccCiInfo.getCi().getCiCode());
            oceanSystem.setSystemNum(ciAttrs.get(systemMap.getString("systemNum")));
            oceanSystem.setSystemName(ciAttrs.get(systemMap.getString("systemName")));
            oceanSystem.setSystemShortName(ciAttrs.get(systemMap.getString("systemShortName")));
            oceanSystem.setBusinessUnit(ciAttrs.get(systemMap.getString("businessUnit")));
            oceanSystem.setBuildTeam(ciAttrs.get(systemMap.getString("buildTeam")));
            oceanSystem.setSystemStatus(ciAttrs.get(systemMap.getString("systemStatus")));
            oceanSystem.setOperateStatus(ciAttrs.get(systemMap.getString("operateStatus")));
            oceanSystem.setSystemType(ciAttrs.get(systemMap.getString("systemType")));
            oceanSystem.setSourceCreateTime(ccCiInfo.getCi().getCreateTime());
            oceanSystem.setSourceModifyTime(ccCiInfo.getCi().getModifyTime());
            oceanSystems.add(oceanSystem);

        }
        oceanSystemService.deleteAndSave(oceanSystems);
        log.info("同步系统数据结束。。。。。。");
    }

    /**
     * 同步项目资产至数据库，项目数量大概每年300左右，采用先删后增（因为没有物理删除）
     * @param config
     */
    void syncProject(String config) {
        log.info("开始同步项目数据。。。。。。");

        // region 配置项检查
        JSONObject jsonConfig = JSON.parseObject(config);
        String projectClassName = jsonConfig.getJSONObject("classMap").getString("项目");
        if (BinaryUtils.isEmpty(projectClassName)) {
            log.error("syncProject 无法获取视图配置项：项目");
            return;
        }
        /**
         * 属性字段
         */
        JSONObject projectMap = jsonConfig.getJSONObject("projectMap");
        if (BinaryUtils.isEmpty(projectMap)) {
            log.error("syncProject 无法获取视图配置项：projectMap");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("internalCode"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.internalCode");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("preReviewNum"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.preReviewNum");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("projectName"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.projectName");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("projectOwner"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.projectOwner");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("preReviewStatus"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.preReviewStatus");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("reviewId"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.reviewId");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("reviewStartTime"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.reviewStartTime");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("reviewEndTime"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.reviewEndTime");
            return;
        }
        if (BinaryUtils.isEmpty(projectMap.getString("archReviewStatus"))) {
            log.error("syncProject 无法获取视图配置项：projectMap.archReviewStatus");
            return;
        }
        // endregion

        // 查询EA系统中对应的对象分类
        CCcCiClass cCcCiClass = new CCcCiClass();
        cCcCiClass.setClassNameEqual(projectClassName);
        List<CcCiClassInfo> ccCiClassInfos = ciClassSvc.queryCiClassInfoList(1L, cCcCiClass, null, false);
        if (null == ccCiClassInfos || ccCiClassInfos.size() == 0) {
            log.error("EA系统中不存在[{}]的对象分类", projectClassName);
            return;
        }
        Long projectClassId = ccCiClassInfos.get(0).getCiClass().getId();

        // 查询项目资产数据
        CCcCi cdt = new CCcCi();
        cdt.setClassId(projectClassId);
        List<CcCiInfo> ccCiInfos = iciSwitchSvc.queryCiInfoList(1l, cdt, null, false, false, LibType.DESIGN);
        List<OceanProject> oceanProjects = new ArrayList<>();
        for (CcCiInfo ccCiInfo : ccCiInfos) {
            Map<String, String> ciAttrs = ccCiInfo.getAttrs();
            OceanProject project = new OceanProject();
            project.setCiCode(ccCiInfo.getCi().getCiCode());
            project.setInternalCode(ciAttrs.get(projectMap.getString("internalCode")));
            project.setPreReviewNum(ciAttrs.get(projectMap.getString("preReviewNum")));
            project.setProjectName(ciAttrs.get(projectMap.getString("projectName")));
            if (!BinaryUtils.isEmpty(ciAttrs.get(projectMap.getString("projectOwner")))) {
                List<JSONObject> owners = JSONObject.parseArray(ciAttrs.get(projectMap.getString("projectOwner")), JSONObject.class);
                project.setProjectOwner(owners.get(0).getString("loginCode"));
            }
            project.setPreReviewStatus(ciAttrs.get(projectMap.getString("preReviewStatus")));
            project.setReviewId(ciAttrs.get(projectMap.getString("reviewId")));
            project.setReviewStartTime(ciAttrs.get(projectMap.getString("reviewStartTime")));
            project.setReviewEndTime(ciAttrs.get(projectMap.getString("reviewEndTime")));
            project.setArchReviewStatus(ciAttrs.get(projectMap.getString("archReviewStatus")));
            project.setSourceCreateTime(ccCiInfo.getCi().getCreateTime());
            project.setSourceModifyTime(ccCiInfo.getCi().getModifyTime());

            oceanProjects.add(project);
        }
        oceanProjectService.deleteAndSave(oceanProjects);
        log.info("同步项目数据结束。。。。。。");
    }

    void syncDiagram() {
        log.info("开始同步视图数据。。。。。。");
        /**
         * 查询已发布的视图
         */
        BoolQueryBuilder diagramQuery = QueryBuilders.boolQuery();
        diagramQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        diagramQuery.must(QueryBuilders.termQuery("status", 1));
        diagramQuery.must(QueryBuilders.termQuery("historyVersionFlag", 1));
        // 视图类型 1:普通视图 3: 公共模板 4:个人模板
        diagramQuery.must(QueryBuilders.termsQuery("diagramType", Lists.newArrayList(1,2,3,4)));
        diagramQuery.must(QueryBuilders.termQuery("isOpen", 1));
        diagramQuery.must(QueryBuilders.existsQuery("ownerCode"));

        List<ESDiagram> diagrams = esDiagramDao.getListByQueryScroll(diagramQuery);
        Set<Long> artifactIds = new HashSet<>();
        Set<String> diagramEnergies = new HashSet<>();
        for (ESDiagram each : diagrams) {
            if(!BinaryUtils.isEmpty(each.getViewType())){
                artifactIds.add(Long.parseLong(each.getViewType()));
            }
            diagramEnergies.add(each.getDEnergy());
        }
        // 根据制品id制品，再与视图一一匹配。
        List<EamArtifact> eamArtifacts = iEamArtifactSvc.queryArtifactListByIds(Lists.newArrayList(artifactIds), 1);
        Map<Long, EamArtifact> artifactMap = eamArtifacts.stream().collect(Collectors.toMap(EamArtifact::getId, each -> each, (k1, k2) -> k1));

        // region 查询视图关联资产信息
        // 根据视图id查询关联资产id
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("diagramEnergy.keyword", diagramEnergies));
        List<EamDiagramRelationSys> diagramRelations = eamDiagramRelationSysDao.getListByQueryScroll(queryBuilder);
        Set<String> ciCodeSet = diagramRelations.stream().map(EamDiagramRelationSys::getEsSysId).collect(Collectors.toSet());
        String[] ciCodeArray = ciCodeSet.toArray(new String[0]);
        // 根据资产ciCode查询资产列表
        CCcCi cdt = new CCcCi();
        cdt.setCiCodes(ciCodeArray);
        List<CcCiInfo> ccCiInfos = iciSwitchSvc.queryCiInfoList(1l, cdt, null, false, true, LibType.DESIGN);
        // 创建资产ciCode到资产信息的映射
        Map<String, Map<String, String>> ciCodeToInfoMap = new HashMap<>();
        for (CcCiInfo ccCiInfo : ccCiInfos) {
            Map<String, String> map = new HashMap<>();
            map.put("ciCode", ccCiInfo.getCi().getCiCode());
            map.put("ciName", getCIShowName(ccCiInfo));
            map.put("className", ccCiInfo.getCiClass().getClassName());
            ciCodeToInfoMap.put(ccCiInfo.getCi().getCiCode(), map);
        }
        // 创建视图id到资产信息的映射
        Map<String, String> diagramEnergyToCiCodeMap = diagramRelations.stream().collect(Collectors.toMap(EamDiagramRelationSys::getDiagramEnergy, each -> each.getEsSysId(), (k1, k2) -> k1));
        Map<String, Map<String, String>> diagramEnergyToCiInfoMap = new HashMap<>();
        for (Map.Entry<String, String> entry : diagramEnergyToCiCodeMap.entrySet()) {
            String diagramEnergy = entry.getKey();
            String ciCode = entry.getValue();
            if (ciCodeToInfoMap.containsKey(ciCode)) {
                diagramEnergyToCiInfoMap.put(diagramEnergy, ciCodeToInfoMap.get(ciCode));
            }
        }
        // endregion

        /**
         * 组织视图保存数据
         */
        List<OceanDiagram> oceanDiagrams = new ArrayList<>();
        for (ESDiagram diagram : diagrams) {
            OceanDiagram oceanDiagram = new OceanDiagram();
            oceanDiagram.setDiagramId(diagram.getDEnergy());
            oceanDiagram.setDiagramName(diagram.getName());
            oceanDiagram.setCreator(diagram.getCreator());
            oceanDiagram.setArtifactId(diagram.getViewType());
            oceanDiagram.setArtifactName("");
            if (!BinaryUtils.isEmpty(diagram.getViewType())) {
                //查询视图中绑定的制品类型
                EamArtifact artifact = artifactMap.get(Long.valueOf(diagram.getViewType()));
                if(!BinaryUtils.isEmpty(artifact)){
                    oceanDiagram.setArtifactName(artifact.getArtifactName());
                }
            }
            oceanDiagram.setAssetType("");
            oceanDiagram.setAssetName("");
            oceanDiagram.setAssetId("");
            if (diagramEnergyToCiInfoMap.get(diagram.getDEnergy()) != null) {
                Map<String, String> ciMap = diagramEnergyToCiInfoMap.get(diagram.getDEnergy());
                oceanDiagram.setAssetType(ciMap.get("className"));
                oceanDiagram.setAssetName(ciMap.get("ciName"));
                oceanDiagram.setAssetId(ciMap.get("ciCode"));
            }
            oceanDiagram.setPublishStatus("已发布");
            oceanDiagram.setPublishTime(String.valueOf(diagram.getModifyTime()));
            oceanDiagram.setSourceCreateTime(diagram.getCreateTime());
            oceanDiagram.setSourceModifyTime(diagram.getModifyTime());
            oceanDiagrams.add(oceanDiagram);
        }

        /**
         * 视图是物理删除的 增量同步很麻烦
         * 目前先用先删后增
         */
        oceanDiagramService.deleteAndSave(oceanDiagrams);
        //        oceanDiagramService.syncData(oceanDiagrams, isFirst, diagramIds);
        log.info("同步视图数据结束。。。。。。");
    }


    /**
     * 获取资产名称
     * @param ciInfo
     * @return
     */
    private String getCIShowName(CcCiInfo ciInfo) {
        String ciLabel = ciInfo.getCi().getCiLabel();
        List<String> labels = JSONObject.parseArray(ciLabel, String.class);
        if (StringUtils.isBlank(ciLabel) || CollectionUtils.isEmpty(labels)) {
            return ciInfo.getCiClass().getClassName();
        }
        return String.join(",", labels);
    }
}
